package websocket

import (
	"encoding/json"
	"net/url"

	"github.com/gorilla/websocket"
)

type Client interface {
	Close() error

	Send(v interface{}) error

	//Read(&data)序列化写入data中
	Read(v interface{}) error
}

type client struct {
	*websocket.Conn

	host string
	opt  *dialOption
}

// Close implements Client.
// Subtle: this method shadows the method (*Conn).Close of client.Conn.
func (c *client) Close() error {
	return c.Conn.Close()
}

// Read implements Client.
func (c *client) Read(v interface{}) error {
	_, msg, err := c.Conn.ReadMessage()
	if err != nil {
		return err
	}
	return json.Unmarshal(msg, v)
}

// Send implements Client.
func (c *client) Send(v interface{}) error {
	data, err := json.Marshal(v)
	if err != nil {
		return err
	}
	err = c.WriteMessage(websocket.TextMessage, data)
	if err == nil {
		return nil
	}

	//重连发送
	conn, err := c.Dial()
	if err != nil {
		return err
	}
	c.Conn = conn
	return c.WriteMessage(websocket.TextMessage, data)
}

func NewClient(host string, opts ...DialOption) *client {
	opt := newDialOption(opts...)

	c := client{
		Conn: nil,
		host: host,
		opt:  opt,
	}
	conn, err := c.Dial()
	if err != nil {
		panic(err)
	}
	c.Conn = conn
	return &c
}

func (c *client) Dial() (*websocket.Conn, error) {
	u := url.URL{Scheme: "ws", Host: c.host, Path: c.opt.pattern}
	conn, _, err := websocket.DefaultDialer.Dial(u.String(), c.opt.header)
	if err != nil {
		return nil, err
	}
	return conn, nil
}

var _ (Client) = (*client)(nil)
